//
//  JSONModel.m
//  niuPei
//
//  Created by hh on 15/6/7.
//  Copyright (c) 2015年 hh. All rights reserved.
//

#import "JSONModel.h"
#import <objc/runtime.h>

@implementation JSONModel 

-(instancetype)initWithDictionary:(NSMutableDictionary *)jsonDictionary
{
    self = [super init];
    if (self) {
        [self setValuesForKeysWithDictionary:jsonDictionary];
    }
    return self;
}

- (instancetype)initWithJSON:(NSString *)json
{
    self = [super init];
    NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    id d = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&err];
    if (err) {
        NSLog(@"json解析出错:%@",err);
        return self;
    }
    if ([d isKindOfClass:[NSArray class]]) {
        NSLog(@"json不应该是数组");
    }else if([d isKindOfClass:[NSDictionary class]]){
        [self setValuesForKeysWithDictionary:d];
    }
    return self;
}

- (NSString *)toJSON
{
    NSDictionary *dict = [self toDictionary];
    NSError *err;
    NSData *res = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&err];
    if (err) {
        NSLog(@"转json出错：%@",err);
        return nil;
    }
    NSString *json = [[NSString alloc] initWithData:res encoding:NSUTF8StringEncoding];
    json = [json stringByReplacingOccurrencesOfString:@" " withString:@""];
    json = [json stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    return json;
}

- (NSDictionary *)toDictionary
{
    NSArray<NSString *> *propertyList = [self getPropertyListForEncode];
    NSMutableDictionary *dict = [NSMutableDictionary new];
    for (NSString *str in propertyList) {
        id value = [self valueForKey:str];
        if ([value isKindOfClass:[NSArray class]] && [value count] > 0 && [(id)[value firstObject] respondsToSelector:@selector(toDictionary)]) {
            NSMutableArray *arr = [NSMutableArray new];
            for (id item in value) {
                [arr addObject:[item toDictionary]];
            }
            dict[str] = arr;
        }else{
            dict[str] = [value respondsToSelector:@selector(toDictionary)] ? [value toDictionary] : value;
        }
    }
    
    return dict;
}

- (void)setValue:(id)value forKey:(NSString *)key
{
//    NSLog(@"key:%@",key);
    Class cls = [self getPropertyClass:key];
    if (!cls && ![key isEqualToString:@"id"]) {
        [super setValue:value forKey:key];
        return;
    }
//    NSLog(@"%@ %@->%@",NSStringFromClass(cls), key, value);
    if ([value isKindOfClass:[NSArray class]]) {
        Class dataClass = [self getSubDataClassInArrayForKey:key];
        if (!dataClass) {
            return [super setValue:value forKey:key];
        }
        NSMutableArray *arr = [NSMutableArray new];
        for (id json in value) {
            if ([json isKindOfClass:dataClass]) {
                [arr addObject:json];
            }else{
                [arr addObject:[[dataClass alloc] initWithDictionary:json]];
            }
        }
        [super setValue:arr forKey:key];
    }else if ([value isKindOfClass:[NSDictionary class]]){
        objc_property_t pt = class_getProperty(self.class, [key cStringUsingEncoding:NSUTF8StringEncoding]);
        NSString *clsString = [NSString stringWithCString:property_getAttributes(pt) encoding:NSUTF8StringEncoding];
        NSRange endR = [clsString rangeOfString:@","];
        NSUInteger end = endR.location - 1;
        clsString = [clsString substringWithRange:NSMakeRange(3, end - 3)];
//         NSLog(@"class:%@",clsString);
        Class dataClass = NSClassFromString(clsString);
        if (dataClass == NSDictionary.class || dataClass == [NSString class]) {
            
            if ([key isEqualToString:@"id"]) {
                [super setValue:value forKey:@"ID"];
            }else{
                [super setValue:value forKey:key];
            }
            
        }else{
            [super setValue:[[dataClass alloc] initWithDictionary:value] forKey:key];
        }
    }else{
//        Class cls = [self getPropertyClass:key];
//        if (!cls) {
//            [super setValue:value forKey:key];
//            return;
//        }
//        NSLog(@"%@ %@->%@",NSStringFromClass(cls), key, value);
        if (![value isKindOfClass:cls] && cls != [NSNumber class] && ![key isEqualToString:@"id"]) {
         //   NSLog(@"类型不匹配！%@ %@->%@", cls, key, value);
            if (cls == [NSArray class] || [cls isSubclassOfClass:[NSArray class]]) {
                value = @[];
                [super setValue:value forKey:key];
                return;
            }
        }
        if ([key isEqualToString:@"id"]) {
            [super setValue:value forKey:@"ID"];
        }else if ([key isEqualToString:@"itemtypelist"] && [value isKindOfClass:[NSString class]]) {
            [super setValue:@[] forKey:@"itemtypelist"];
        }else{
            
            if (!([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNull class]] || value == nil)) {
                [super setValue:[NSString stringWithFormat:@"%@",value] forKey:key];
            }else{
                 [super setValue:value forKey:key];
            }                       
        }
        
    }
}

- (NSString *)description
{
    NSArray *propertyList = [self getPropertyListForEncode];
    NSMutableString *str = [NSMutableString new];
    [str appendString:@"\n{"];
    for (NSString *propertyKey in propertyList) {
        id value = [self valueForKey:propertyKey];
        if (![value isKindOfClass:[NSString class]]) {
            value = [value description];
        }
        [str appendFormat:@"\t%@:%@\n",propertyKey,value];
//        NSLog(@"%@:%@",propertyKey,value);
    }
    [str appendString:@"}"];
    return str;
}

- (NSString *)debugDescription{
    return [self description];
}

- (void)printAllproperty{
    
    NSArray *propertyList = [self getPropertyListForEncode];

    NSLog(@"*****属性**********");
    for (NSString *propertyKey in propertyList) {
        NSLog(@"@property (nonatomic,strong) NSString *%@",propertyKey);     
    }
    NSLog(@"*****属性**********");
}

- (NSDictionary *)getSubDataClassInArrayForKey:(NSString *)key
{
    return nil;
}

-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    if ([NSStringFromClass([self class]) isEqualToString:@"Page"] && [key isEqualToString:@"items"]) {
        return;
    }
//    NSLog(@"%@ 缺少的属性: %@:%@", NSStringFromClass([self class]),key,value);
}

- (NSArray *)getPropertyListForEncode
{
    // test:
//    NSLog(@"<%@ properties>:",self.class);
    Class cls = self.class;
    NSMutableArray *arr = [NSMutableArray new];
    while (![cls isEqual:JSONModel.class]) {
        unsigned int count;
        objc_property_t *properties = class_copyPropertyList(cls, &count);
        if (properties == NULL) {
            continue;
        }
        for (int i = 0; i < count; i++) {
            NSString *key = @(property_getName(properties[i]));
//            NSString *attr = NSStringFromClass([self getPropertyClass:key]);
//            NSLog(@"%@, %@",key,attr);
            [arr addObject:key];
        }
        
        free(properties);
        
        cls = cls.superclass;
    }
    return arr;
}

- (Class)getPropertyClass:(NSString *)prop
{
    objc_property_t p = class_getProperty(self.class, prop.UTF8String);
//    const char *x = property_getAttributes(p);
    const char *x = property_copyAttributeValue(p, "T");

    NSString *res = x ? @(x) : nil;
    return res.length > 2 ? NSClassFromString([res substringWithRange:NSMakeRange(2, res.length - 3)]) : nil;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    NSArray *propertyList = [self getPropertyListForEncode];
    for (NSString *propertyKey in propertyList) {
        // may have bugs: property maybe BOOL、int etc
        id value = [self valueForKey:propertyKey];
//        NSLog(@"%@:%@",propertyKey,value);
        [aCoder encodeObject:value forKey:propertyKey];
    }
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    NSArray *propertyList = [self getPropertyListForEncode];
    for (NSString *propertyKey in propertyList) {
        // may have bugs: property maybe BOOL、int etc
        id value = [aDecoder decodeObjectForKey:propertyKey];
        [self setValue:value forKey:propertyKey];
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
    id copy = [self.class allocWithZone:zone];
    NSArray *arr = [self getPropertyListForEncode];
    for (NSString *key in arr) {
        NSLog(@"%@",key);
        id value = [self valueForKey:key];
        [copy setValue:[value copy] forKey:key];
    }
    return copy;
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    //
    id mutableCopy = [self.class allocWithZone:zone];
    NSArray *arr = [self getPropertyListForEncode];
    for (NSString *key in arr) {
        id value = [self valueForKey:key];
        id nValue = [value isKindOfClass:[NSObject class]] && [value respondsToSelector:@selector(mutableCopy)] ? [value mutableCopy] : value;
        [mutableCopy setValue:nValue forKey:key];
    }
    return mutableCopy;
}

@end
